package com.rbac.web.controller;

import com.rbac.web.exception.ApplicationException;
import com.rbac.web.model.User;
import com.rbac.web.model.req.LoginReq;
import com.rbac.web.model.res.UserGetOneRes;
import com.rbac.web.service.IRoleService;
import com.rbac.web.service.IUserService;
import com.rbac.web.service.IUserTokenService;
import com.rbac.web.util.IdentifyCodeUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpHeaders;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author gengaoliu
 */
@RestController
@RequestMapping("/sys")
@RequiredArgsConstructor
@Transactional(rollbackFor = Exception.class)
@Tag(name = "登陆入口", description = "刘澳港")
public class LoginController {
  private final IUserService userService;
  private final IUserTokenService tokenService;
  private final IRoleService roleService;

  @GetMapping("/code/{username}")
  @Operation(summary = "获取图形验证码")
  public void getImgCode(
      HttpServletResponse response,
      @PathVariable @Validated @NotNull(message = "username must not be null") String username)
      throws NoSuchAlgorithmException, IOException {
    if (Boolean.TRUE.equals(tokenService.haveCode(username))) {
      throw ApplicationException.createException("获取验证码的时间应该大于1分钟");
    }
    response.setHeader("Pragma", "No-cache");
    response.setHeader("Cache-Control", "No-cache");
    response.setDateHeader("Expires", 0);
    response.setContentType("image/png");
    IdentifyCodeUtil ic = IdentifyCodeUtil.getInstance();
    BufferedImage img = ic.getIdentifyImage();
    tokenService.saveImageCode(username, ic.getCode());
    ImageIO.write(img, "JPEG", response.getOutputStream());
  }

  @PostMapping("/login")
  @Operation(summary = "登陆")
  public String login(@RequestBody @Validated LoginReq req) {
    String imgCode = tokenService.getImgCode(req.getUsername());
    if (!req.getImgCode().toUpperCase().equals(imgCode)) {
      throw ApplicationException.createException("验证码错误");
    }
    User user = userService.findByUsername(req.getUsername()).orElse(User.builder().build());
    if (null == user.getUsername()) {
      throw ApplicationException.createException("用户名" + req.getUsername() + "不存在");
    }
    if (!user.getPassword().equals(req.getPassword())) {
      throw ApplicationException.createException("密码错误，请重新输入");
    }
    String token = UUID.randomUUID().toString();
    tokenService.saveToken(token, user);
    tokenService.deleteImgCode(req.getUsername());
    return token;
  }

  @PostMapping("logout")
  @Operation(summary = "登出")
  public void logout(HttpServletRequest request) {
    String token = request.getHeader(HttpHeaders.AUTHORIZATION);
    tokenService.deleteToken(token);
  }

  @GetMapping("/info/{token}")
  @Operation(summary = "查看当前登录账号信息")
  public UserGetOneRes getCurUser(@PathVariable("token") String token) {
    User user = tokenService.getUser(token);
    UserGetOneRes res = UserGetOneRes.from(user);
    List<String> roles = new ArrayList<>();
    List<Integer> roleId = res.getRoleId();
    for (Integer id : roleId) {
      roleService.selectById(id).ifPresent(role -> {
        roles.add(role.getName());
      });
    }
    res.setRoles(roles);
    return res;
  }
}
